library(tidyverse)
abund <- read.table("../../data/E-WADES/depths_M3.tsv", header=T,
row.names=1, sep="\t", check.names=F)
meta_sample <- read.table("../../data/E-WADES/meta_sample.tsv", header=T,
row.names=1, sep="\t", check.names=F) %>%
select(City, Replicate_Bigger, Date) %>%
rownames_to_column("sample")
taxon <- read.table("../../data/E-WADES/taxonomy.tsv", header=T,
row.names=1, sep="\t", check.names=F)
all(rownames(abund)==meta_sample$sample) &
all(colnames(abund)==rownames(taxon))
[1] TRUE
Remove replicates from abundance matrix
abund <- abund[meta_sample$Replicate_Bigger,]
meta_sample <- meta_sample[meta_sample$Replicate_Bigger,]
Aggregate to Genus Rank
genus_abund <- abund %>% rownames_to_column("sample") %>%
pivot_longer(-sample, names_to="Species", values_to="count") %>%
left_join(taxon%>%rownames_to_column("SpeciesID") %>% select(SpeciesID,Genus) %>%
rename(Species=SpeciesID), by="Species") %>%
reframe(count=sum(count), .by=c("sample","Genus")) %>%
pivot_wider(names_from=Genus, values_from=count) %>%
column_to_rownames("sample")
genus_rel_abund <- data.frame(genus_abund/rowSums(genus_abund))
subset_genus <- colSums(genus_abund) %>% sort %>% tail(10) %>% names
color_genus <- rownames(qualpalr::qualpal(n = length(subset_genus),
colorspace = list(h = c(0,360),
s = c(.25,.6),
l = c(.45,.85)))$RGB) %>%
stats::setNames(subset_genus)
color_genus <- c(color_genus, "Other"="#A6A6A6")
color_genus
Trichococcus Psychrobacter Giesbergeria Neisseria Aliarcobacter Comamonas Ottowia
"#7CB932" "#4231B6" "#B43632" "#BFD1EF" "#4879A2" "#D7A2B0" "#B939A8"
Acinetobacter Pseudomonas_E Acidovorax Other
"#CA8F42" "#42B7A1" "#EDE6C3" "#A6A6A6"
data_composition <- genus_rel_abund %>%
rownames_to_column("sample") %>%
pivot_longer(-sample, names_to="genus", values_to="relative") %>%
mutate(genus = if_else(genus %in% subset_genus, genus, "Other")) %>%
left_join(meta_sample, by="sample") %>%
filter(Replicate_Bigger) %>%
reframe(relative=sum(relative), .by=c("sample","genus","City")) %>%
group_by(sample) %>%
mutate(Pseudomonas_E_rel = sum(relative[genus == "Pseudomonas_E"])) %>%
ungroup() %>%
arrange(Pseudomonas_E_rel) %>%
mutate(sample_fct = factor(sample, levels = unique(sample)))
p.composition <- data_composition %>%
ggplot(aes(x=sample_fct,y=relative,fill=genus)) +
geom_bar(stat="identity", color=rgb(0,0,0,.25), linewidth=.25) +
scale_fill_manual(values=color_genus,
labels = function(x) paste0("<i>", x, "</i>")) +
theme_minimal() +
theme(legend.position="bottom",
axis.text.x=element_blank(),
axis.ticks.x=element_blank(),
legend.text = ggtext::element_markdown()) +
ylab("Genus\nComposition") +
labs(fill="Genus") +
xlab("Samples") +
ggnewscale::new_scale_fill() +
geom_tile(data = data_composition,
aes(x = sample, y = -0.03, fill = City),
height = 0.03, width = 1, inherit.aes = FALSE)
p.composition

Dimensionality Reduction
# Calculate the distance matrix with bray-curtis and aitchison
dist.bray <- vegan::vegdist(abund, "bray") %>% as.dist
dist.aitc <- abund %>%
zCompositions::cmultRepl() %>%
vegan::vegdist(method = "aitchison")
No. adjusted imputations: 148
PCOA
pcoa.bray <- stats::cmdscale(dist.bray, eig=T, add=T)
pcoa.aitc <- stats::cmdscale(dist.aitc, eig=T, add=T)
Plot with Aitchison Distance
centroids.pcoa.aitc <- pcoa.aitc$points %>% as_tibble %>%
cbind("City"=meta_sample$City) %>%
reframe(V1=mean(V1),
V2=mean(V2),
.by=City)
varExplained_aitc <- 100 * (pcoa.aitc$eig / sum(pcoa.aitc$eig)) %>%
round(2)
p.pcoa.aitc <- pcoa.aitc$points %>% as_tibble %>%
cbind("City"=meta_sample$City) %>%
ggplot(aes(x=V1,y=V2, color=City)) +
geom_point(size=3) +
stat_ellipse() +
geom_point(data=centroids.pcoa.aitc, shape=21, size=5, color="black",
aes(fill=City)) +
theme_minimal() +
xlab(paste("PCoA1 (~",varExplained_aitc[1],"%)", sep="")) +
ylab(paste("PCoA2 (~",varExplained_aitc[2],"%)", sep="")) +
theme(legend.position="bottom") +
theme(axis.text=element_text(size=10),
axis.title=element_text(size=12))
p.pcoa.aitc

varExplained_bray <- 100 * (pcoa.bray$eig / sum(pcoa.bray$eig)) %>%
round(2)
p.pcoa.bray <- pcoa.bray$points %>% as_tibble %>%
as_tibble() %>% mutate(Pseudomonas_E=genus_rel_abund[, "Pseudomonas_E"]) %>%
ggplot(aes(x=V1, y=V2, fill=Pseudomonas_E)) +
geom_point(size=4, shape = 21, color = "black") +
theme_minimal() +
xlab(paste("PCoA1 (~",varExplained_bray[1],"%)", sep="")) +
ylab(paste("PCoA2 (~",varExplained_bray[2],"%)", sep="")) +
#scale_color_viridis_c(option = "C") +
scale_fill_gradient(
low = "#2C3E50",
high = color_genus["Pseudomonas_E"] # Same color associated to Pseudomonas_E genus
) +
theme(axis.text=element_text(size=10),
axis.title=element_text(size=12)) +
theme(legend.position="bottom") +
labs(fill = expression("Relative Composition of "*italic("Pseudomonas_E")))
p.pcoa.bray

Adonis 2
meta_sample <- genus_rel_abund %>% as_tibble(rownames = "sample") %>%
select(sample, Pseudomonas_E) %>%
right_join(meta_sample, by = "sample") %>%
mutate(City = case_when(
str_detect(City, "Copenaghen") ~ "Copenaghen",
TRUE ~ City
))
vegan::adonis2(dist.aitc ~ City + Pseudomonas_E, data = meta_sample,
permutations = 10^3, by = "margin")
Permutation test for adonis under reduced model
Marginal effects of terms
Permutation: free
Number of permutations: 1000
vegan::adonis2(formula = dist.aitc ~ City + Pseudomonas_E, data = meta_sample, permutations = 10^3, by = "margin")
Df SumOfSqs R2 F Pr(>F)
City 4 265729 0.32571 32.543 0.000999 ***
Pseudomonas_E 1 35103 0.04303 17.196 0.000999 ***
Residual 229 467480 0.57300
Total 234 815846 1.00000
---
Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
vegan::adonis2(dist.bray ~ City + Pseudomonas_E, data = meta_sample,
permutations = 10^3, by = "margin")
Permutation test for adonis under reduced model
Marginal effects of terms
Permutation: free
Number of permutations: 1000
vegan::adonis2(formula = dist.bray ~ City + Pseudomonas_E, data = meta_sample, permutations = 10^3, by = "margin")
Df SumOfSqs R2 F Pr(>F)
City 4 7.833 0.16663 15.177 0.000999 ***
Pseudomonas_E 1 6.299 0.13401 48.822 0.000999 ***
Residual 229 29.548 0.62856
Total 234 47.009 1.00000
---
Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
UMAP
library(uwot)
set.seed(42)
umap.bray <- uwot::umap(as.dist(dist.bray), min_dist = .5)
set.seed(42)
umap.aitc <- uwot::umap(as.dist(dist.aitc), min_dist = .5)
p.umap.aitc <- umap.aitc %>% as_tibble %>%
cbind("City"=meta_sample$City) %>%
ggplot(aes(x=V1,y=V2, fill=City)) +
geom_point(size=4, shape = 21, alpha = .75) +
theme_minimal() +
xlab("UMAP-1") + ylab("UMAP-2") +
theme(legend.position="bottom") +
theme(axis.text=element_text(size=10),
axis.title=element_text(size=12))
p.umap.aitc

p.umap.bray <- umap.bray %>% as_tibble %>%
mutate(Pseudomonas_E=genus_rel_abund[, "Pseudomonas_E"]) %>%
ggplot(aes(x=V1, y=V2, fill=Pseudomonas_E)) +
geom_point(size=4, shape = 21, color = "black") +
theme_minimal() +
xlab("UMAP-1") + ylab("UMAP-2") +
#scale_color_viridis_c(option = "C") +
scale_fill_gradient(
low = "#2C3E50",
high = color_genus["Pseudomonas_E"] # Same color associated to Pseudomonas_E genus
) +
theme(axis.text=element_text(size=10),
axis.title=element_text(size=12)) +
theme(legend.position="bottom") +
labs(fill = expression("Relative Composition of "*italic("Pseudomonas_E")))
p.umap <- ggpubr::ggarrange(
p.umap.bray + theme(plot.margin = margin(b = 15, t = 5)) + ggtitle("E-WADES Bray-Curtis"),
p.umap.aitc + ggtitle("E-WADES Aitchison"),
ncol = 2
)
p.umap

Review
pcoa.euc <- dist(abund) %>%
stats::cmdscale(eig=T, add=T)
pcoa.JSD <- philentropy::distance(abund, method = "jensen-shannon") %>%
stats::cmdscale(eig=T, add=T)
G3;Metric: 'jensen-shannon' using unit: 'log'; comparing: 235 vectors.
g
pcoa.CAN <- vegan::vegdist(abund, method = "canberra") %>%
stats::cmdscale(eig=T, add=T)
pcoa.HEL <- vegan::vegdist(abund, method = "hellinger") %>%
stats::cmdscale(eig=T, add=T)
plot.PCOA.pseo <- function(pcoa, meta_sample, genus_abun){
varExplained <- 100 * (pcoa$eig / sum(pcoa$eig)) %>%
round(2)
p <- pcoa$points %>% as_tibble %>%
as_tibble() %>% mutate(Pseudomonas_E=genus_abun[, "Pseudomonas_E"]) %>%
ggplot(aes(x=V1, y=V2, color=Pseudomonas_E)) +
geom_point(size=2) +
theme_minimal() +
xlab(paste("PCoA1 (~",varExplained[1],"%)", sep="")) +
ylab(paste("PCoA2 (~",varExplained[2],"%)", sep="")) +
scale_fill_gradient(
low = "#2C3E50",
high = color_genus["Pseudomonas_E"] # Same color associated to Pseudomonas_E genus
) +
theme(legend.position="none") +
theme(title = element_text(size = 16))
return(p)
}
plot.PCOA.city <- function(pcoa, meta_sample){
varExplained_aitc <- 100 * (pcoa$eig / sum(pcoa$eig)) %>%
round(2)
p <- pcoa$points %>% as_tibble %>%
cbind("City" = meta_sample$City) %>%
ggplot(aes(x=V1,y=V2, color=City)) +
geom_point(size=2) +
theme_minimal() +
xlab(paste("PCoA1 (~",varExplained_aitc[1],"%)", sep="")) +
ylab(paste("PCoA2 (~",varExplained_aitc[2],"%)", sep="")) +
theme(legend.position="none") +
theme(title = element_text(size = 16))
}
p.euc.pseo <- plot.PCOA.pseo(pcoa.euc, meta_sample, genus_rel_abund)
p.JSD.pseo <- plot.PCOA.pseo(pcoa.JSD, meta_sample, genus_rel_abund)
p.CAN.pseo <- plot.PCOA.pseo(pcoa.CAN, meta_sample, genus_rel_abund)
p.HEL.pseo <- plot.PCOA.pseo(pcoa.HEL, meta_sample, genus_rel_abund)
p.AIT.pseo <- plot.PCOA.pseo(pcoa.aitc, meta_sample, genus_rel_abund)
p.BRA.pseo <- plot.PCOA.pseo(pcoa.bray, meta_sample, genus_rel_abund)
p.euc.city <- plot.PCOA.city(pcoa.euc, meta_sample)
p.JSD.city <- plot.PCOA.city(pcoa.JSD, meta_sample)
p.CAN.city <- plot.PCOA.city(pcoa.CAN, meta_sample)
p.HEL.city <- plot.PCOA.city(pcoa.HEL, meta_sample)
p.AIT.city <- plot.PCOA.city(pcoa.aitc, meta_sample)
p.BRA.city <- plot.PCOA.city(pcoa.bray, meta_sample)
spacer_title <- ggplot() +
theme_void() +
ggtitle("E-WADES Pseudomonadaceae") +
theme(plot.title = element_text(hjust = 0.5, size = 20, face = "bold"))
p.pseo <- ggpubr::ggarrange(
p.euc.pseo + ggtitle("Euclidian"),
p.JSD.pseo + ggtitle("Jensen-Shannon"),
p.CAN.pseo + ggtitle("Canberra"),
p.HEL.pseo + ggtitle("Hellinger"),
p.BRA.pseo + ggtitle("Bray-Curtis"),
p.AIT.pseo + ggtitle("Aitchison"),
ncol = 6, legend = "none"
)
p.pseo <- ggpubr::ggarrange(spacer_title, p.pseo, nrow = 2, heights = c(.1, .9))
p.pseo

spacer_title <- ggplot() +
theme_void() +
ggtitle("E-WADES City") +
theme(plot.title = element_text(hjust = 0.5, size = 20, face = "bold"))
p.city <- ggpubr::ggarrange(
p.euc.city + ggtitle("Euclidian"),
p.JSD.city + ggtitle("Jensen-Shannon"),
p.CAN.city + ggtitle("Canberra"),
p.HEL.city + ggtitle("Hellinger"),
p.BRA.city + ggtitle("Bray-Curtis"),
p.AIT.city + ggtitle("Aitchison"),
ncol = 6, common.legend = T, legend = "none"
)
p.city <- ggpubr::ggarrange(spacer_title, p.city, nrow = 2, heights = c(.1, .9))
p.city

pall <- ggpubr::ggarrange(p.pseo, p.city, nrow = 2)
pall

png("../Supplementary/EWADES_pcoa_more_metrics.png", width = 2*7200, height = 2*2700, res = 2*300)
pall
dev.off()
null device
1
LS0tCnRpdGxlOiAiUiBOb3RlYm9vayIKb3V0cHV0OiBodG1sX25vdGVib29rCi0tLQoKYGBge3IsIG1lc3NhZ2U9RkFMU0V9CmxpYnJhcnkodGlkeXZlcnNlKQpgYGAKCmBgYHtyLCBtZXNzYWdlPUZBTFNFfQphYnVuZCA8LSByZWFkLnRhYmxlKCIuLi8uLi9kYXRhL0UtV0FERVMvZGVwdGhzX00zLnRzdiIsIGhlYWRlcj1ULAogICAgICAgICAgICAgICAgICAgIHJvdy5uYW1lcz0xLCBzZXA9Ilx0IiwgY2hlY2submFtZXM9RikKbWV0YV9zYW1wbGUgPC0gcmVhZC50YWJsZSgiLi4vLi4vZGF0YS9FLVdBREVTL21ldGFfc2FtcGxlLnRzdiIsIGhlYWRlcj1ULAogICAgICAgICAgICAgICAgICAgIHJvdy5uYW1lcz0xLCBzZXA9Ilx0IiwgY2hlY2submFtZXM9RikgJT4lCiAgc2VsZWN0KENpdHksIFJlcGxpY2F0ZV9CaWdnZXIsIERhdGUpICU+JQogIHJvd25hbWVzX3RvX2NvbHVtbigic2FtcGxlIikKdGF4b24gPC0gIHJlYWQudGFibGUoIi4uLy4uL2RhdGEvRS1XQURFUy90YXhvbm9teS50c3YiLCBoZWFkZXI9VCwKICAgICAgICAgICAgICAgICAgICByb3cubmFtZXM9MSwgc2VwPSJcdCIsIGNoZWNrLm5hbWVzPUYpCmBgYAoKYGBge3J9CmFsbChyb3duYW1lcyhhYnVuZCk9PW1ldGFfc2FtcGxlJHNhbXBsZSkgJgphbGwoY29sbmFtZXMoYWJ1bmQpPT1yb3duYW1lcyh0YXhvbikpCmBgYAoKIyMjIFJlbW92ZSByZXBsaWNhdGVzIGZyb20gYWJ1bmRhbmNlIG1hdHJpeAoKYGBge3J9CmFidW5kIDwtIGFidW5kW21ldGFfc2FtcGxlJFJlcGxpY2F0ZV9CaWdnZXIsXQptZXRhX3NhbXBsZSA8LSBtZXRhX3NhbXBsZVttZXRhX3NhbXBsZSRSZXBsaWNhdGVfQmlnZ2VyLF0KYGBgCgoKIyMgQWdncmVnYXRlIHRvIEdlbnVzIFJhbmsKCmBgYHtyfQpnZW51c19hYnVuZCA8LSBhYnVuZCAlPiUgcm93bmFtZXNfdG9fY29sdW1uKCJzYW1wbGUiKSAlPiUKICBwaXZvdF9sb25nZXIoLXNhbXBsZSwgbmFtZXNfdG89IlNwZWNpZXMiLCB2YWx1ZXNfdG89ImNvdW50IikgJT4lCiAgbGVmdF9qb2luKHRheG9uJT4lcm93bmFtZXNfdG9fY29sdW1uKCJTcGVjaWVzSUQiKSAlPiUgc2VsZWN0KFNwZWNpZXNJRCxHZW51cykgJT4lCiAgICAgICAgICAgICAgcmVuYW1lKFNwZWNpZXM9U3BlY2llc0lEKSwgYnk9IlNwZWNpZXMiKSAlPiUKICByZWZyYW1lKGNvdW50PXN1bShjb3VudCksIC5ieT1jKCJzYW1wbGUiLCJHZW51cyIpKSAlPiUKICBwaXZvdF93aWRlcihuYW1lc19mcm9tPUdlbnVzLCB2YWx1ZXNfZnJvbT1jb3VudCkgJT4lCiAgY29sdW1uX3RvX3Jvd25hbWVzKCJzYW1wbGUiKQoKZ2VudXNfcmVsX2FidW5kIDwtIGRhdGEuZnJhbWUoZ2VudXNfYWJ1bmQvcm93U3VtcyhnZW51c19hYnVuZCkpCmBgYAoKYGBge3J9CnN1YnNldF9nZW51cyA8LSBjb2xTdW1zKGdlbnVzX2FidW5kKSAlPiUgc29ydCAlPiUgdGFpbCgxMCkgJT4lIG5hbWVzCmBgYAoKYGBge3J9CmNvbG9yX2dlbnVzIDwtIHJvd25hbWVzKHF1YWxwYWxyOjpxdWFscGFsKG4gPSBsZW5ndGgoc3Vic2V0X2dlbnVzKSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbG9yc3BhY2UgPSBsaXN0KGggPSBjKDAsMzYwKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcyA9IGMoLjI1LC42KSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbCA9IGMoLjQ1LC44NSkpKSRSR0IpICU+JQogIHN0YXRzOjpzZXROYW1lcyhzdWJzZXRfZ2VudXMpCmNvbG9yX2dlbnVzIDwtIGMoY29sb3JfZ2VudXMsICJPdGhlciI9IiNBNkE2QTYiKQpjb2xvcl9nZW51cwpgYGAKCmBgYHtyfQpkYXRhX2NvbXBvc2l0aW9uIDwtIGdlbnVzX3JlbF9hYnVuZCAlPiUKICByb3duYW1lc190b19jb2x1bW4oInNhbXBsZSIpICU+JQogIHBpdm90X2xvbmdlcigtc2FtcGxlLCBuYW1lc190bz0iZ2VudXMiLCB2YWx1ZXNfdG89InJlbGF0aXZlIikgJT4lCiAgbXV0YXRlKGdlbnVzID0gaWZfZWxzZShnZW51cyAlaW4lIHN1YnNldF9nZW51cywgZ2VudXMsICJPdGhlciIpKSAlPiUKICBsZWZ0X2pvaW4obWV0YV9zYW1wbGUsIGJ5PSJzYW1wbGUiKSAlPiUKICBmaWx0ZXIoUmVwbGljYXRlX0JpZ2dlcikgJT4lCiAgcmVmcmFtZShyZWxhdGl2ZT1zdW0ocmVsYXRpdmUpLCAuYnk9Yygic2FtcGxlIiwiZ2VudXMiLCJDaXR5IikpICU+JQogIGdyb3VwX2J5KHNhbXBsZSkgJT4lCiAgbXV0YXRlKFBzZXVkb21vbmFzX0VfcmVsID0gc3VtKHJlbGF0aXZlW2dlbnVzID09ICJQc2V1ZG9tb25hc19FIl0pKSAlPiUKICB1bmdyb3VwKCkgJT4lCiAgYXJyYW5nZShQc2V1ZG9tb25hc19FX3JlbCkgJT4lCiAgbXV0YXRlKHNhbXBsZV9mY3QgPSBmYWN0b3Ioc2FtcGxlLCBsZXZlbHMgPSB1bmlxdWUoc2FtcGxlKSkpCgpwLmNvbXBvc2l0aW9uIDwtIGRhdGFfY29tcG9zaXRpb24gJT4lCiAgZ2dwbG90KGFlcyh4PXNhbXBsZV9mY3QseT1yZWxhdGl2ZSxmaWxsPWdlbnVzKSkgKwogICAgZ2VvbV9iYXIoc3RhdD0iaWRlbnRpdHkiLCBjb2xvcj1yZ2IoMCwwLDAsLjI1KSwgbGluZXdpZHRoPS4yNSkgKwogICAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzPWNvbG9yX2dlbnVzLAogICAgICAgICAgICAgICAgICAgICAgbGFiZWxzID0gZnVuY3Rpb24oeCkgcGFzdGUwKCI8aT4iLCB4LCAiPC9pPiIpKSArCiAgICB0aGVtZV9taW5pbWFsKCkgKwogICAgdGhlbWUobGVnZW5kLnBvc2l0aW9uPSJib3R0b20iLAogICAgICAgICAgYXhpcy50ZXh0Lng9ZWxlbWVudF9ibGFuaygpLAogICAgICAgICAgYXhpcy50aWNrcy54PWVsZW1lbnRfYmxhbmsoKSwKICAgICAgICAgIGxlZ2VuZC50ZXh0ID0gZ2d0ZXh0OjplbGVtZW50X21hcmtkb3duKCkpICsKICB5bGFiKCJHZW51c1xuQ29tcG9zaXRpb24iKSArCiAgbGFicyhmaWxsPSJHZW51cyIpICsKICB4bGFiKCJTYW1wbGVzIikgKwogIGdnbmV3c2NhbGU6Om5ld19zY2FsZV9maWxsKCkgKwogIGdlb21fdGlsZShkYXRhID0gZGF0YV9jb21wb3NpdGlvbiwKICAgICAgICAgICAgYWVzKHggPSBzYW1wbGUsIHkgPSAtMC4wMywgZmlsbCA9IENpdHkpLCAKICAgICAgICAgICAgaGVpZ2h0ID0gMC4wMywgd2lkdGggPSAxLCBpbmhlcml0LmFlcyA9IEZBTFNFKSAKcC5jb21wb3NpdGlvbgpgYGAKCiMjIERpbWVuc2lvbmFsaXR5IFJlZHVjdGlvbgoKYGBge3J9CiMgQ2FsY3VsYXRlIHRoZSBkaXN0YW5jZSBtYXRyaXggd2l0aCBicmF5LWN1cnRpcyBhbmQgYWl0Y2hpc29uCmRpc3QuYnJheSA8LSB2ZWdhbjo6dmVnZGlzdChhYnVuZCwgImJyYXkiKSAlPiUgYXMuZGlzdApkaXN0LmFpdGMgPC0gYWJ1bmQgJT4lIAogIHpDb21wb3NpdGlvbnM6OmNtdWx0UmVwbCgpICU+JQogIHZlZ2FuOjp2ZWdkaXN0KG1ldGhvZCA9ICJhaXRjaGlzb24iKSAKYGBgCgojIyBQQ09BCgpgYGB7cn0KcGNvYS5icmF5IDwtIHN0YXRzOjpjbWRzY2FsZShkaXN0LmJyYXksIGVpZz1ULCBhZGQ9VCkKcGNvYS5haXRjIDwtIHN0YXRzOjpjbWRzY2FsZShkaXN0LmFpdGMsIGVpZz1ULCBhZGQ9VCkKYGBgCgojIyBQbG90IHdpdGggQWl0Y2hpc29uIERpc3RhbmNlCgpgYGB7ciwgd2FybmluZz1GQUxTRX0KY2VudHJvaWRzLnBjb2EuYWl0YyA8LSBwY29hLmFpdGMkcG9pbnRzICU+JSBhc190aWJibGUgJT4lCiAgY2JpbmQoIkNpdHkiPW1ldGFfc2FtcGxlJENpdHkpICU+JQogIHJlZnJhbWUoVjE9bWVhbihWMSksIAogICAgICAgICAgVjI9bWVhbihWMiksCiAgICAgICAgICAuYnk9Q2l0eSkKCnZhckV4cGxhaW5lZF9haXRjIDwtIDEwMCAqIChwY29hLmFpdGMkZWlnIC8gc3VtKHBjb2EuYWl0YyRlaWcpKSAlPiUKICByb3VuZCgyKQoKcC5wY29hLmFpdGMgPC0gIHBjb2EuYWl0YyRwb2ludHMgJT4lIGFzX3RpYmJsZSAlPiUgCiAgY2JpbmQoIkNpdHkiPW1ldGFfc2FtcGxlJENpdHkpICU+JQogIGdncGxvdChhZXMoeD1WMSx5PVYyLCBjb2xvcj1DaXR5KSkgKwogIGdlb21fcG9pbnQoc2l6ZT0zKSArCiAgc3RhdF9lbGxpcHNlKCkgKwogIGdlb21fcG9pbnQoZGF0YT1jZW50cm9pZHMucGNvYS5haXRjLCBzaGFwZT0yMSwgc2l6ZT01LCBjb2xvcj0iYmxhY2siLAogICAgICAgICAgICAgYWVzKGZpbGw9Q2l0eSkpICsKICB0aGVtZV9taW5pbWFsKCkgKwogIHhsYWIocGFzdGUoIlBDb0ExICh+Iix2YXJFeHBsYWluZWRfYWl0Y1sxXSwiJSkiLCBzZXA9IiIpKSArCiAgeWxhYihwYXN0ZSgiUENvQTIgKH4iLHZhckV4cGxhaW5lZF9haXRjWzJdLCIlKSIsIHNlcD0iIikpICsKICB0aGVtZShsZWdlbmQucG9zaXRpb249ImJvdHRvbSIpICsKICB0aGVtZShheGlzLnRleHQ9ZWxlbWVudF90ZXh0KHNpemU9MTApLAogICAgICAgIGF4aXMudGl0bGU9ZWxlbWVudF90ZXh0KHNpemU9MTIpKQoKcC5wY29hLmFpdGMKYGBgCgpgYGB7cn0KdmFyRXhwbGFpbmVkX2JyYXkgPC0gMTAwICogKHBjb2EuYnJheSRlaWcgLyBzdW0ocGNvYS5icmF5JGVpZykpICU+JQogIHJvdW5kKDIpCgpwLnBjb2EuYnJheSA8LSBwY29hLmJyYXkkcG9pbnRzICU+JSBhc190aWJibGUgJT4lIAogIGFzX3RpYmJsZSgpICU+JSBtdXRhdGUoUHNldWRvbW9uYXNfRT1nZW51c19yZWxfYWJ1bmRbLCAiUHNldWRvbW9uYXNfRSJdKSAlPiUKICBnZ3Bsb3QoYWVzKHg9VjEsIHk9VjIsIGZpbGw9UHNldWRvbW9uYXNfRSkpICsKICAgIGdlb21fcG9pbnQoc2l6ZT00LCBzaGFwZSA9IDIxLCBjb2xvciA9ICJibGFjayIpICsKICAgIHRoZW1lX21pbmltYWwoKSArCiAgICB4bGFiKHBhc3RlKCJQQ29BMSAofiIsdmFyRXhwbGFpbmVkX2JyYXlbMV0sIiUpIiwgc2VwPSIiKSkgKwogICAgeWxhYihwYXN0ZSgiUENvQTIgKH4iLHZhckV4cGxhaW5lZF9icmF5WzJdLCIlKSIsIHNlcD0iIikpICsKICAgICNzY2FsZV9jb2xvcl92aXJpZGlzX2Mob3B0aW9uID0gIkMiKSArCiAgICAgc2NhbGVfZmlsbF9ncmFkaWVudCgKICAgICAgbG93ID0gIiMyQzNFNTAiLCAgCiAgICAgIGhpZ2ggPSBjb2xvcl9nZW51c1siUHNldWRvbW9uYXNfRSJdICAjIFNhbWUgY29sb3IgYXNzb2NpYXRlZCB0byBQc2V1ZG9tb25hc19FIGdlbnVzCiAgICApICsKICAgIHRoZW1lKGF4aXMudGV4dD1lbGVtZW50X3RleHQoc2l6ZT0xMCksCiAgICAgICAgICBheGlzLnRpdGxlPWVsZW1lbnRfdGV4dChzaXplPTEyKSkgKwogICAgdGhlbWUobGVnZW5kLnBvc2l0aW9uPSJib3R0b20iKSArCiAgICBsYWJzKGZpbGwgPSBleHByZXNzaW9uKCJSZWxhdGl2ZSBDb21wb3NpdGlvbiBvZiAiKml0YWxpYygiUHNldWRvbW9uYXNfRSIpKSkKcC5wY29hLmJyYXkKYGBgCgoKIyMgTWVyZ2UgdGhlIGZpZ3VyZXMKCmBgYHtyLCBmaWcud2lkdGg9MTMuMywgZmlnLmhlaWdodD0xMH0KcDEgPC0gcC5jb21wb3NpdGlvbiArIGd1aWRlcyhmaWxsPWd1aWRlX2xlZ2VuZChuY29sPTYpKQoKcDIgPC0gZ2dwdWJyOjpnZ2FycmFuZ2UocC5wY29hLmJyYXkgKyB0aGVtZShsZWdlbmQubWFyZ2luID0gbWFyZ2luKHQgPSAyMCwgYiA9IDEwKSksCiAgICAgICAgICAgICAgICAgICAgICAgIHAucGNvYS5haXRjLCBuY29sPTIsIGxhYmVscz1jKCJCIiwiQyIpKQoKcGFsbCA8LSBnZ3B1YnI6OmdnYXJyYW5nZShwMSwgcDIsIAogICAgICAgICAgICAgICAgICAgICAgICAgIG5jb2w9MSwgbGFiZWxzPWMoIkEiLCIiKSwKICAgICAgICAgICAgICAgICAgICAgICAgICBoZWlnaHRzPWMoMC40LDAuNikpCnBhbGwKYGBgCgoKYGBge3J9CnBuZyhmaWxlbmFtZT0iRS1XQURFU19wY29hX21ldHJpY3MucG5nIiwgd2lkdGg9ODAwMCwgaGVpZ2h0PTYwMDAsIHJlcz02MDApCnBhbGwKZGV2Lm9mZigpCgpwZGYoZmlsZT0iRS1XQURFU19wY29hX21ldHJpY3MucGRmIiwgd2lkdGg9MTMuMywgaGVpZ2h0PTEwKQpwYWxsCmRldi5vZmYoKQpgYGAKCiMjIEFkb25pcyAyCgpgYGB7cn0KbWV0YV9zYW1wbGUgPC0gZ2VudXNfcmVsX2FidW5kICU+JSBhc190aWJibGUocm93bmFtZXMgPSAic2FtcGxlIikgJT4lCiAgc2VsZWN0KHNhbXBsZSwgUHNldWRvbW9uYXNfRSkgJT4lCiAgcmlnaHRfam9pbihtZXRhX3NhbXBsZSwgYnkgPSAic2FtcGxlIikgJT4lCiAgbXV0YXRlKENpdHkgPSBjYXNlX3doZW4oCiAgICBzdHJfZGV0ZWN0KENpdHksICJDb3BlbmFnaGVuIikgfiAiQ29wZW5hZ2hlbiIsCiAgICBUUlVFIH4gQ2l0eQogICkpCmBgYAoKYGBge3J9CnZlZ2FuOjphZG9uaXMyKGRpc3QuYWl0YyB+IENpdHkgKyBQc2V1ZG9tb25hc19FLCBkYXRhID0gbWV0YV9zYW1wbGUsIAogICAgICAgICAgICAgICBwZXJtdXRhdGlvbnMgPSAxMF4zLCBieSA9ICJtYXJnaW4iKQpgYGAKCmBgYHtyfQp2ZWdhbjo6YWRvbmlzMihkaXN0LmJyYXkgfiBDaXR5ICsgUHNldWRvbW9uYXNfRSwgZGF0YSA9IG1ldGFfc2FtcGxlLCAKICAgICAgICAgICAgICAgcGVybXV0YXRpb25zID0gMTBeMywgYnkgPSAibWFyZ2luIikKYGBgCgoKIyMgVU1BUAoKYGBge3IsbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KbGlicmFyeSh1d290KQpzZXQuc2VlZCg0MikKdW1hcC5icmF5IDwtIHV3b3Q6OnVtYXAoYXMuZGlzdChkaXN0LmJyYXkpLCBtaW5fZGlzdCA9IC41KQoKc2V0LnNlZWQoNDIpCnVtYXAuYWl0YyA8LSB1d290Ojp1bWFwKGFzLmRpc3QoZGlzdC5haXRjKSwgbWluX2Rpc3QgPSAuNSkKYGBgCgpgYGB7cn0KcC51bWFwLmFpdGMgPC0gdW1hcC5haXRjICU+JSBhc190aWJibGUgJT4lIAogIGNiaW5kKCJDaXR5Ij1tZXRhX3NhbXBsZSRDaXR5KSAlPiUKICBnZ3Bsb3QoYWVzKHg9VjEseT1WMiwgZmlsbD1DaXR5KSkgKwogIGdlb21fcG9pbnQoc2l6ZT00LCBzaGFwZSA9IDIxLCBhbHBoYSA9IC43NSkgKwogIHRoZW1lX21pbmltYWwoKSArCiAgeGxhYigiVU1BUC0xIikgKyB5bGFiKCJVTUFQLTIiKSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uPSJib3R0b20iKSArCiAgdGhlbWUoYXhpcy50ZXh0PWVsZW1lbnRfdGV4dChzaXplPTEwKSwKICAgICAgICBheGlzLnRpdGxlPWVsZW1lbnRfdGV4dChzaXplPTEyKSkKCnAudW1hcC5haXRjCmBgYAoKYGBge3J9CnAudW1hcC5icmF5IDwtIHVtYXAuYnJheSAlPiUgYXNfdGliYmxlICU+JSAKICAgIG11dGF0ZShQc2V1ZG9tb25hc19FPWdlbnVzX3JlbF9hYnVuZFssICJQc2V1ZG9tb25hc19FIl0pICU+JQogICAgZ2dwbG90KGFlcyh4PVYxLCB5PVYyLCBmaWxsPVBzZXVkb21vbmFzX0UpKSArCiAgICBnZW9tX3BvaW50KHNpemU9NCwgc2hhcGUgPSAyMSwgY29sb3IgPSAiYmxhY2siKSArCiAgICB0aGVtZV9taW5pbWFsKCkgKwogICAgeGxhYigiVU1BUC0xIikgKyB5bGFiKCJVTUFQLTIiKSArCiAgICAjc2NhbGVfY29sb3JfdmlyaWRpc19jKG9wdGlvbiA9ICJDIikgKwogICAgIHNjYWxlX2ZpbGxfZ3JhZGllbnQoCiAgICAgIGxvdyA9ICIjMkMzRTUwIiwgIAogICAgICBoaWdoID0gY29sb3JfZ2VudXNbIlBzZXVkb21vbmFzX0UiXSAgIyBTYW1lIGNvbG9yIGFzc29jaWF0ZWQgdG8gUHNldWRvbW9uYXNfRSBnZW51cwogICAgKSArCiAgICB0aGVtZShheGlzLnRleHQ9ZWxlbWVudF90ZXh0KHNpemU9MTApLAogICAgICAgICAgYXhpcy50aXRsZT1lbGVtZW50X3RleHQoc2l6ZT0xMikpICsKICAgIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbj0iYm90dG9tIikgKwogICAgbGFicyhmaWxsID0gZXhwcmVzc2lvbigiUmVsYXRpdmUgQ29tcG9zaXRpb24gb2YgIippdGFsaWMoIlBzZXVkb21vbmFzX0UiKSkpCmBgYAoKYGBge3IsIGZpZy53aWR0aD0xMCwgZmlnLmhlaWdodD01fQpwLnVtYXAgPC0gZ2dwdWJyOjpnZ2FycmFuZ2UoCiAgcC51bWFwLmJyYXkgKyB0aGVtZShwbG90Lm1hcmdpbiA9IG1hcmdpbihiID0gMTUsIHQgPSA1KSkgKyBnZ3RpdGxlKCJFLVdBREVTIEJyYXktQ3VydGlzIiksIAogIHAudW1hcC5haXRjICsgZ2d0aXRsZSgiRS1XQURFUyBBaXRjaGlzb24iKSwgCiAgbmNvbCA9IDIKKQpwLnVtYXAKYGBgCgpgYGB7cn0KcG5nKGZpbGVuYW1lID0gIi4uL1N1cHBsZW1lbnRhcnkvRVdBREVTX3VtYXBfbWV0cmljcy5wbmciLCB3aWR0aCA9IDMwMDAsIGhlaWdodCA9IDE4MDAsIHJlcyA9IDMwMCkKcC51bWFwCmRldi5vZmYoKQpgYGAKCiMjIFJldmlldwoKYGBge3J9CnBjb2EuZXVjIDwtIGRpc3QoYWJ1bmQpICU+JQogIHN0YXRzOjpjbWRzY2FsZShlaWc9VCwgYWRkPVQpCnBjb2EuSlNEIDwtIHBoaWxlbnRyb3B5OjpkaXN0YW5jZShhYnVuZCwgbWV0aG9kID0gImplbnNlbi1zaGFubm9uIikgJT4lCiAgc3RhdHM6OmNtZHNjYWxlKGVpZz1ULCBhZGQ9VCkKcGNvYS5DQU4gPC0gdmVnYW46OnZlZ2Rpc3QoYWJ1bmQsIG1ldGhvZCA9ICJjYW5iZXJyYSIpICU+JQogIHN0YXRzOjpjbWRzY2FsZShlaWc9VCwgYWRkPVQpCnBjb2EuSEVMIDwtIHZlZ2FuOjp2ZWdkaXN0KGFidW5kLCBtZXRob2QgPSAiaGVsbGluZ2VyIikgJT4lCiAgc3RhdHM6OmNtZHNjYWxlKGVpZz1ULCBhZGQ9VCkKYGBgCgpgYGB7cn0KcGxvdC5QQ09BLnBzZW8gPC0gZnVuY3Rpb24ocGNvYSwgbWV0YV9zYW1wbGUsIGdlbnVzX2FidW4pewogIAogIHZhckV4cGxhaW5lZCA8LSAxMDAgKiAocGNvYSRlaWcgLyBzdW0ocGNvYSRlaWcpKSAlPiUKICAgIHJvdW5kKDIpCgogIHAgPC0gcGNvYSRwb2ludHMgJT4lIGFzX3RpYmJsZSAlPiUgCiAgICBhc190aWJibGUoKSAlPiUgbXV0YXRlKFBzZXVkb21vbmFzX0U9Z2VudXNfYWJ1blssICJQc2V1ZG9tb25hc19FIl0pICU+JQogICAgZ2dwbG90KGFlcyh4PVYxLCB5PVYyLCBjb2xvcj1Qc2V1ZG9tb25hc19FKSkgKwogICAgZ2VvbV9wb2ludChzaXplPTIpICsKICAgIHRoZW1lX21pbmltYWwoKSArCiAgICB4bGFiKHBhc3RlKCJQQ29BMSAofiIsdmFyRXhwbGFpbmVkWzFdLCIlKSIsIHNlcD0iIikpICsKICAgIHlsYWIocGFzdGUoIlBDb0EyICh+Iix2YXJFeHBsYWluZWRbMl0sIiUpIiwgc2VwPSIiKSkgKwogICAgc2NhbGVfZmlsbF9ncmFkaWVudCgKICAgICAgICBsb3cgPSAiIzJDM0U1MCIsICAKICAgICAgICBoaWdoID0gY29sb3JfZ2VudXNbIlBzZXVkb21vbmFzX0UiXSAgIyBTYW1lIGNvbG9yIGFzc29jaWF0ZWQgdG8gUHNldWRvbW9uYXNfRSBnZW51cwogICAgICApICsKICAgIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbj0ibm9uZSIpICsKICAgIHRoZW1lKHRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAxNikpCgogIHJldHVybihwKQp9CmBgYAoKYGBge3J9CnBsb3QuUENPQS5jaXR5IDwtIGZ1bmN0aW9uKHBjb2EsIG1ldGFfc2FtcGxlKXsKICAKICB2YXJFeHBsYWluZWRfYWl0YyA8LSAxMDAgKiAocGNvYSRlaWcgLyBzdW0ocGNvYSRlaWcpKSAlPiUKICAgIHJvdW5kKDIpCgogIHAgPC0gIHBjb2EkcG9pbnRzICU+JSBhc190aWJibGUgJT4lIAogICAgY2JpbmQoIkNpdHkiID0gbWV0YV9zYW1wbGUkQ2l0eSkgJT4lCiAgICBnZ3Bsb3QoYWVzKHg9VjEseT1WMiwgY29sb3I9Q2l0eSkpICsKICAgIGdlb21fcG9pbnQoc2l6ZT0yKSArCiAgICB0aGVtZV9taW5pbWFsKCkgKwogICAgeGxhYihwYXN0ZSgiUENvQTEgKH4iLHZhckV4cGxhaW5lZF9haXRjWzFdLCIlKSIsIHNlcD0iIikpICsKICAgIHlsYWIocGFzdGUoIlBDb0EyICh+Iix2YXJFeHBsYWluZWRfYWl0Y1syXSwiJSkiLCBzZXA9IiIpKSArCiAgICB0aGVtZShsZWdlbmQucG9zaXRpb249Im5vbmUiKSArCiAgICB0aGVtZSh0aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTYpKQp9CmBgYAoKCmBgYHtyfQpwLmV1Yy5wc2VvIDwtIHBsb3QuUENPQS5wc2VvKHBjb2EuZXVjLCBtZXRhX3NhbXBsZSwgZ2VudXNfcmVsX2FidW5kKQpwLkpTRC5wc2VvIDwtIHBsb3QuUENPQS5wc2VvKHBjb2EuSlNELCBtZXRhX3NhbXBsZSwgZ2VudXNfcmVsX2FidW5kKQpwLkNBTi5wc2VvIDwtIHBsb3QuUENPQS5wc2VvKHBjb2EuQ0FOLCBtZXRhX3NhbXBsZSwgZ2VudXNfcmVsX2FidW5kKQpwLkhFTC5wc2VvIDwtIHBsb3QuUENPQS5wc2VvKHBjb2EuSEVMLCBtZXRhX3NhbXBsZSwgZ2VudXNfcmVsX2FidW5kKQpwLkFJVC5wc2VvIDwtIHBsb3QuUENPQS5wc2VvKHBjb2EuYWl0YywgbWV0YV9zYW1wbGUsIGdlbnVzX3JlbF9hYnVuZCkKcC5CUkEucHNlbyA8LSBwbG90LlBDT0EucHNlbyhwY29hLmJyYXksIG1ldGFfc2FtcGxlLCBnZW51c19yZWxfYWJ1bmQpCmBgYAoKYGBge3J9CnAuZXVjLmNpdHkgPC0gcGxvdC5QQ09BLmNpdHkocGNvYS5ldWMsIG1ldGFfc2FtcGxlKQpwLkpTRC5jaXR5IDwtIHBsb3QuUENPQS5jaXR5KHBjb2EuSlNELCBtZXRhX3NhbXBsZSkKcC5DQU4uY2l0eSA8LSBwbG90LlBDT0EuY2l0eShwY29hLkNBTiwgbWV0YV9zYW1wbGUpCnAuSEVMLmNpdHkgPC0gcGxvdC5QQ09BLmNpdHkocGNvYS5IRUwsIG1ldGFfc2FtcGxlKQpwLkFJVC5jaXR5IDwtIHBsb3QuUENPQS5jaXR5KHBjb2EuYWl0YywgbWV0YV9zYW1wbGUpCnAuQlJBLmNpdHkgPC0gcGxvdC5QQ09BLmNpdHkocGNvYS5icmF5LCBtZXRhX3NhbXBsZSkKYGBgCgpgYGB7cn0Kc3BhY2VyX3RpdGxlIDwtIGdncGxvdCgpICsgCiAgdGhlbWVfdm9pZCgpICsKICBnZ3RpdGxlKCJFLVdBREVTIFBzZXVkb21vbmFkYWNlYWUiKSArCiAgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSwgc2l6ZSA9IDIwLCBmYWNlID0gImJvbGQiKSkKYGBgCgpgYGB7ciwgZmlnLndpZHRoPTI0LCBmaWcuaGVpZ2h0PTQuNX0KcC5wc2VvIDwtIGdncHVicjo6Z2dhcnJhbmdlKAogIHAuZXVjLnBzZW8gKyBnZ3RpdGxlKCJFdWNsaWRpYW4iKSwKICBwLkpTRC5wc2VvICsgZ2d0aXRsZSgiSmVuc2VuLVNoYW5ub24iKSwgCiAgcC5DQU4ucHNlbyArIGdndGl0bGUoIkNhbmJlcnJhIiksIAogIHAuSEVMLnBzZW8gKyBnZ3RpdGxlKCJIZWxsaW5nZXIiKSwKICBwLkJSQS5wc2VvICsgZ2d0aXRsZSgiQnJheS1DdXJ0aXMiKSwKICBwLkFJVC5wc2VvICsgZ2d0aXRsZSgiQWl0Y2hpc29uIiksIAogIG5jb2wgPSA2LCBsZWdlbmQgPSAibm9uZSIKKQpwLnBzZW8gPC0gZ2dwdWJyOjpnZ2FycmFuZ2Uoc3BhY2VyX3RpdGxlLCBwLnBzZW8sIG5yb3cgPSAyLCBoZWlnaHRzID0gYyguMSwgLjkpKQpwLnBzZW8KYGBgCgpgYGB7cn0Kc3BhY2VyX3RpdGxlIDwtIGdncGxvdCgpICsgCiAgdGhlbWVfdm9pZCgpICsKICBnZ3RpdGxlKCJFLVdBREVTIENpdHkiKSArCiAgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSwgc2l6ZSA9IDIwLCBmYWNlID0gImJvbGQiKSkKYGBgCgpgYGB7ciwgZmlnLndpZHRoPTI0LCBmaWcuaGVpZ2h0PTQuNX0KcC5jaXR5IDwtIGdncHVicjo6Z2dhcnJhbmdlKAogIHAuZXVjLmNpdHkgKyBnZ3RpdGxlKCJFdWNsaWRpYW4iKSwgCiAgcC5KU0QuY2l0eSArIGdndGl0bGUoIkplbnNlbi1TaGFubm9uIiksIAogIHAuQ0FOLmNpdHkgKyBnZ3RpdGxlKCJDYW5iZXJyYSIpLCAKICBwLkhFTC5jaXR5ICsgZ2d0aXRsZSgiSGVsbGluZ2VyIiksCiAgcC5CUkEuY2l0eSArIGdndGl0bGUoIkJyYXktQ3VydGlzIiksCiAgcC5BSVQuY2l0eSArIGdndGl0bGUoIkFpdGNoaXNvbiIpLCAKICBuY29sID0gNiwgY29tbW9uLmxlZ2VuZCA9IFQsIGxlZ2VuZCA9ICJub25lIgopCnAuY2l0eSA8LSBnZ3B1YnI6OmdnYXJyYW5nZShzcGFjZXJfdGl0bGUsIHAuY2l0eSwgbnJvdyA9IDIsIGhlaWdodHMgPSBjKC4xLCAuOSkpCnAuY2l0eQpgYGAKCmBgYHtyLCBmaWcud2lkdGg9MjQsIGZpZy5oZWlnaHQ9OX0KcGFsbCA8LSBnZ3B1YnI6OmdnYXJyYW5nZShwLnBzZW8sIHAuY2l0eSwgbnJvdyA9IDIpCnBhbGwKYGBgCgpgYGB7cn0KcG5nKCIuLi9TdXBwbGVtZW50YXJ5L0VXQURFU19wY29hX21vcmVfbWV0cmljcy5wbmciLCB3aWR0aCA9IDIqNzIwMCwgaGVpZ2h0ID0gMioyNzAwLCByZXMgPSAyKjMwMCkKcGFsbApkZXYub2ZmKCkKYGBgCgo=